package main

import (
	"encoding/xml"
	"fmt"
	"github.com/golang/protobuf/proto"
	"go.uber.org/zap"
	"io/ioutil"
	"protohook/hook_proxy"
	KKSG "protohook/ropb"
)

var (
	// 所有服务器的地址
	allServerMapAddress map[int32]string
	// 角色id对应的服务器地址,重连用
	roleId2ServerAddress map[uint64]string
)
const (
	// 重连常用字符串
	kReloginStr = "relogin"
)

// 查询gateip的协议解析
type QueryGateIpParser struct {
	*hook_proxy.EmptyProtocolParser
}

func (p *QueryGateIpParser) Server2Client(buf []byte, customContext interface{}) []byte {
	var res KKSG.QueryGateNewRes
	if err := proto.Unmarshal(buf, &res); err != nil {
		zap.S().Warn("解析协议失败", err)
		return buf
	}
	if allServerMapAddress == nil {
		allServerMapAddress = make(map[int32]string)
	}
	// 把所有的服务器ip，都改成本地的
	for _, s := range res.Allservers {
		// 地址有可能会改变，所以每次请求都赋值没问题
		allServerMapAddress[s.Serverid] = fmt.Sprintf("%s:%d", s.Ip, s.Port)
		s.Ip = "127.0.0.1"
		s.Port = globalXmlConfig.ROHookProxyConf.GateListenPort
	}
	for _, s := range res.Servers {
		if s.Servers != nil {
			s.Servers.Port = globalXmlConfig.ROHookProxyConf.GateListenPort
			s.Servers.Ip = "127.0.0.1"
		}
	}
	if b, err := proto.Marshal(&res); err == nil {
		return b
	}
	return buf
}

type LoginRequestParser struct {
	*hook_proxy.EmptyProtocolParser
}

func (p *LoginRequestParser) Client2Server(buf []byte, customContext interface{}) []byte {
	var arg KKSG.LoginArg
	if err := proto.Unmarshal(buf, &arg); err != nil {
		zap.S().Warn("解析协议失败")
		return buf
	}
	if ctx, ok := customContext.(*RORoleContext); ok {
		// 要连接的服务器的地址
		if v, ok := allServerMapAddress[int32(arg.Gameserverid)]; ok {
			ctx.connectServerAddress = v
		} else {
			ctx.connectServerAddress = kReloginStr
		}
		ctx.openId = arg.Openid
	}
	return buf
}
type SelectRoleNtfParser struct {
	*hook_proxy.EmptyProtocolParser
}
func (p *SelectRoleNtfParser) Server2Client(buf []byte, customContext interface{}) []byte {
	if ctx, ok := customContext.(*RORoleContext); ok {
		var ptcData KKSG.SelectRoleNtfData
		if err := proto.Unmarshal(buf, &ptcData); err == nil {
			ctx.userName = ptcData.RoleData.Brief.Name
			ctx.roleId = ptcData.RoleData.Brief.Roleid
			if nil == roleId2ServerAddress {
				roleId2ServerAddress = make(map[uint64]string)
			}
			roleId2ServerAddress[ctx.roleId] = ctx.connectServerAddress
		}
	}
	return buf
}

/*
// 客户端发起重连
type ReconnectParser struct {
	*hook_proxy.EmptyProtocolParser
}

func (p *ReconnectParser) Client2Server(buf []byte, customContext interface{}) []byte {
	if ctx, ok := customContext.(*RORoleContext); ok {
		var arg KKSG.ReconnArg
		if err := proto.Unmarshal(buf, &arg); err == nil {
			if v, ok := roleId2ServerAddress[arg.Roleid]; ok {
				ctx.connectServerAddress = v
				zap.S().Infof("[重连] 角色[%d] 取到重连地址[%s]", arg.Roleid, v)
				return buf
			} else {
				zap.S().Infof("[重连] 角色[%d] 重连失败", arg.Roleid)
			}
		}
		ctx.connectServerAddress = kReloginStr
	}
	return buf
}

// 服务器发重连数据
type ReconectSyncParser struct {
    *hook_proxy.EmptyProtocolParser
}
func (p *ReconectSyncParser) Server2Client(buf []byte, customContext interface{}) []byte {
	if ctx, ok := customContext.(*RORoleContext); ok {
		var arg KKSG.ReconectSync
		if err := proto.Unmarshal(buf, &arg); err == nil {
			ctx.userName = arg.RoleData.Brief.Name
			ctx.roleId = arg.RoleData.Brief.Roleid
			ctx.openId = arg.RoleData.Brief.AccountID
		}
	}
	return buf
}
*/

//  @Desc: xml配置的协议信息
type ROProtoNode struct {
	Name string `xml:"Name"`
	ProtoId uint32 `xml:"ProtoId"`
	isRpc bool
}

/// protocol.xml
type ROProtoPTCXML struct {
	PtcNodes []ROProtoNode `xml:"PGProtocol"`
}

// rpc.xml
type ROProtoRPCXML struct {
	RpcNodes []ROProtoNode `xml:"PGRpc"`
}

// 全局唯一管理器
type ROProtocolsMgr struct {
	ptcXmlList ROProtoPTCXML
	rpcXmlList ROProtoRPCXML

	// 协议id对应的具体信息   <protoid, node>
	id2Node map[uint32]ROProtoNode
}
//  全局唯一协议管理
var globalROProtoMgr = ROProtocolsMgr{}

func GetProtoNode(protoId uint32) *ROProtoNode {
	if node, ok := globalROProtoMgr.id2Node[protoId]; ok {
		return &node
	}
	return nil
}

// 加载文件之后,初始化好数据
func (mgr *ROProtocolsMgr) afterLoad() bool {
	mgr.id2Node = make(map[uint32]ROProtoNode)
	for _, node := range mgr.ptcXmlList.PtcNodes {
		mgr.id2Node[node.ProtoId] = node
	}
	for _, node := range mgr.rpcXmlList.RpcNodes {
		node.isRpc = true
		mgr.id2Node[node.ProtoId] = node
	}
	return true
}

//  @Desc: 解析协议xml文件
//  @return bool 解析结果
func loadProtocolXML() bool {
	ptcBuf, err := ioutil.ReadFile(globalXmlConfig.ROProtoXMLPath + "protocol.xml")
	if err != nil {
		zap.S().Error("[协议] 找不到ptc协议文件")
		return false
	}
	if err = xml.Unmarshal(ptcBuf, &globalROProtoMgr.ptcXmlList); err != nil {
		zap.S().Error("[协议] 解析ptc协议失败")
		return false
	}
	rpcBuf, err := ioutil.ReadFile(globalXmlConfig.ROProtoXMLPath + "rpc.xml")
	if err != nil {
		zap.S().Error("[协议] 找不到rpc文件")
		return false
	}
	if err = xml.Unmarshal(rpcBuf, &globalROProtoMgr.rpcXmlList); err != nil {
		zap.S().Error("[协议] 解析rpc协议失败")
		return false
	}
	return globalROProtoMgr.afterLoad()
}

//  @Desc: 注册RO的特殊协议
func registerSpecialProtocols() {
	// RpcC2I_QueryGateIPNew
	hook_proxy.RegisterProtocolParser(1128921835, new(QueryGateIpParser))
	// RpcC2T_ClientLoginRequest
	hook_proxy.RegisterProtocolParser(1129625954, new(LoginRequestParser))
	// PtcG2C_SelectRoleNtf
	hook_proxy.RegisterProtocolParser(1195637234, new(SelectRoleNtfParser))
	// RpcC2T_Reconnect
	// hook_proxy.RegisterProtocolParser(1129629483, new(ReconnectParser))
	// PtcG2C_ReconnectSyncNotify
	//hook_proxy.RegisterProtocolParser(1195616830, new(ReconectSyncParser))
}
